using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Text;
using System.Windows.Forms;

using KLATencor.CommonApp.Infrastructure.StateMachine;

using Syncfusion.Windows.Forms.Diagram.Controls;
using Syncfusion.Windows.Forms.Diagram;

using StateMachine_Graphical_Editor.Shapes;
using StateMachine_Graphical_Editor.Graphics_Rendering;
using StateMachine_Graphical_Editor.Forms;

using StateMachine_Graphical_Editor.Utils.Forms_RunTime_Managment;



namespace StateMachine_Graphical_Editor.Forms
{
    /// <summary>
    /// Displays properties of a selected transition
    /// </summary>
    public partial class TransionProperties : Form
    {
        #region Members:

        private GState m_selectedState; //if opened to add a transition to state
        private GTransition m_originalTrans;
        private GTransition m_selectedTransition;
        private NodeCollection m_diagramElements;
        private Model m_model;
        private StateMachine m_machine;

        private Initializer m_initializer;

        #region Constants:
        
        private const String ADD_TRANSITION_TITLE = "Add transion";
        private const String EDIT_TRANSITIONTITLE = "Edit Transition: ";
        private const String TRANSITION_INITIAL_NAME = "Transition";
        
        #endregion

        #endregion

        #region C'tor:

        public TransionProperties(Model model, Initializer initializer, StateMachine machine)
        {
            InitializeComponent();
            this.m_initializer = initializer;
            this.m_machine = machine;
            this.m_model = model;
        }

        #endregion

        #region Event handlers:

        private void cancelButton_Click(object sender, EventArgs e)
        {
            this.Close();
        }

        private void okButton_Click(object sender, EventArgs e)
        {
            if (!validateInput())
                return;

            //TODO when feature enabled - add logic transition to machine!!!!
            //Transition logicTransition = new ......
            //m_machine.Transitions.add(logicTransition);

            //check if src and dst already connected with a transition
            GTransition connector = null;
            
            //TODO - uncomment when feature of adding transitions is ready
            //GTransition gTransition = m_initializer.checkMultipleTransitions(logicTransition);
            
            if (connector != null)
            {
                //TODO - uncomment when feature of adding transitions is ready
                //gTransition.addName(logicTransition.Name);
                //gTransition.MultipleTransitions = true;
            }
            else
            {
                Node src = m_diagramElements.FindNodeByName(this.sourceNameDropDownBox.SelectedItem.ToString());
                Node dst = m_diagramElements.FindNodeByName(this.targetNameDropDownBox.SelectedItem.ToString());

                //add connector only if dst is the parent of the src
                if (!dstIsSrcParent(src, dst))
                {
                    connector = this.m_initializer.connectNodes(src, dst, transitionNameBox.Text, null);
                    //TODO - add to method the possibility to add also the logic transition
                    getTransitionProperties(connector/*, logicTransition*/ );

                    //change an old transition's location on diagram
                    if (m_originalTrans != null)
                        m_model.RemoveChild(m_originalTrans);
                    m_model.AppendChild(connector);
                }
            }
            this.Close();
        }

        private void addGuardButton_Click(object sender, EventArgs e)
        {
            AddGuardForm guardForm = new AddGuardForm(guardTextBox.Text);
            //set old guard if any
            guardForm.GuardStatement = guardTextBox.Text;
            guardForm.ShowDialog(this);
            guardTextBox.Text = guardForm.GuardStatement;
        }

        #endregion

        #region Helper Methods:

        /// <summary>
        /// New transition creation. Set the form's fields with data from the diagram
        /// </summary>
        /// <param name="selected">The selected state to add new transition to</param>
        /// <param name="levelStatesCollection">The "brother" states on this hierarchy level</param>
        /// <param name="diagramElements">The graphical elements on this hierarchy level</param>
        public void setNewTransitionProperties(//updateTransionProperties(
            GState selected, 
            StateCollection levelStatesCollection, 
            NodeCollection diagramElements)
        {
            this.m_selectedState = selected;
            this.m_diagramElements = diagramElements;
            this.Text = ADD_TRANSITION_TITLE + " To " + selected.Name;

            long nextID = getNextTransitionID();
            this.transitionNameBox.Text = TRANSITION_INITIAL_NAME + nextID;
            this.transitionIdBox.Text = nextID.ToString();
            
            //set the source state name
            this.sourceNameDropDownBox.Items.Add(selected.Name);
            this.sourceNameDropDownBox.SelectedItem = selected.Name;
            this.sourceNameDropDownBox.Enabled = false;
            this.sourceNameDropDownBox.AllowDrop = false;
                           
            //add existing state names to the target states box
            if (diagramElements != null)
            {
                foreach (Node s in diagramElements)
                {
                    bool enter = true;
                    if (selected.ParentState!=null && selected.ParentState.Name.Equals(s.Name))
                        enter = false;
                    if (s is GState && enter)
                        targetNameDropDownBox.Items.Add(s.Name);
                }
            }
            sourceNameDropDownBox.Items.Add(selected.Name);

            //default as defined in XSD
            this.transionTypeBox.SelectedItem = "Basic";
        }

        /// <summary>
        /// Editing existing transition. Set the form's fields with data from the diagram
        /// </summary>
        /// <param name="selected">The selected transition to edit</param>
        /// <param name="levelStatesCollection">The "brother" states on this hierarchy level</param></param>
        /// <param name="gStates">The graphical elements on this hierarchy level</param>
        public void setExistingTransitionProperties(//viewAndUpdateTransionProperties(
            GTransition selected, 
            StateCollection levelStatesCollection, 
            NodeCollection gStates)
        {
            this.m_selectedTransition = selected;
            this.m_originalTrans = selected;
            this.m_diagramElements = gStates; 
            
            this.Text = EDIT_TRANSITIONTITLE + selected.Name; //changed

            //check if GState is new or from machine
            if (selected != null) //new state created by user
            {
                //search for source and dst to display in combo boxes
                if (levelStatesCollection != null)
                {
                    foreach (Node s in gStates)
                    {
                        if (s is GState)
                        {
                            String stateName = s.Name;
                            sourceNameDropDownBox.Items.Add(stateName);
                            targetNameDropDownBox.Items.Add(stateName);
                        }
                    }
                }
                this.transitionNameBox.Text = selected.Name;
                this.sourceNameDropDownBox.SelectedItem = ((GState)selected.FromNode).Name;
                this.targetNameDropDownBox.SelectedItem = ((GState)selected.ToNode).Name; 
                this.transitionIdBox.Text = selected.Id.ToString();
                this.abbrevNameBox.Text = selected.AbbrevName;
                this.eventNameBox.Text = selected.EventName;
                
                if (!string.IsNullOrEmpty(selected.Action))
                    this.actionComboBox.SelectedItem = selected.Action;
                
                if (!string.IsNullOrEmpty(selected.Type))
                    this.transionTypeBox.SelectedItem = selected.Type;
                
                this.guardTextBox.Text = selected.Guard;                
            }
        }

        /// <summary>
        /// Add new transition out of the data inserted
        /// </summary>
        /// <param name="connector"></param>
        private void getTransitionProperties(GTransition connector/*, Transition logicTransition */)
        {
            //TODO - when feature is ready
            //connector.LogicTransition = logicTransition;

            //add the XML needed data:
            connector.AbbrevName = this.abbrevNameBox.Text;
            connector.EventName = this.eventNameBox.Text;
            connector.TargetState = this.targetNameDropDownBox.Items[0].ToString();
            connector.SourceState = this.sourceNameDropDownBox.Items[0].ToString();
            connector.Id = Convert.ToInt32(this.transitionIdBox.Text);
            
            if (actionComboBox.SelectedItem != null)
                connector.Action = actionComboBox.SelectedItem.ToString();
            
            if (transionTypeBox.SelectedItem != null)
                connector.Type = transionTypeBox.SelectedItem.ToString();
            
            connector.Guard = guardTextBox.Text;
        }

        /// <summary>
        /// Make sure that all mandatory fields are fed with data
        /// </summary>
        /// <returns>true for valid form, false if not</returns>
        private bool validateInput()
        {
            bool transNameOK = transitionNameBox.Text != null && !transitionNameBox.Text.Equals("");
            bool transIdOK = transitionIdBox.Text != null && !transitionIdBox.Text.Equals("");
            bool dstOK = targetNameDropDownBox.SelectedItem != null;

            if (transNameOK && transIdOK && dstOK)
                return true;

            else
            {
                MessageBox.Show(
                "You must feed a valid name, Id, source state and target state",
                "Validation error:",
                MessageBoxButtons.OK,
                MessageBoxIcon.Error);

                transitionNameLabel.ForeColor = transNameOK ? Color.Black : Color.Red;
                transitionIdLabel.ForeColor = transIdOK ? Color.Black : Color.Red;
                targetLabel.ForeColor = dstOK ? Color.Black : Color.Red;

                return false;
            }

        }

        /// <summary>
        /// Check if parent-child relationship exists between transition's source and target states
        /// </summary>
        /// <param name="src">From state</param>
        /// <param name="dst">to state</param>
        /// <returns>true if target is the source's parent</returns>
        private bool dstIsSrcParent(Node src, Node dst)
        {
            State source = null;
            foreach (State state in m_machine.AllStates)
            {
                if (src.Name.Equals(state.Name))
                {
                    source = state;
                    break;
                }
            }
            return (source != null) && (source.Parent != null) && (source.Parent.Name.Equals(dst.Name));
        }

        /// <summary>
        /// Calculate next possible transition id 
        /// </summary>
        /// <returns></returns>
        private long getNextTransitionID()
        {
            long maxTransionId = 0;
            foreach (Transition tr in m_machine.Transitions)
            {
                maxTransionId = Math.Max(tr.TransitionNumber, maxTransionId);
            }
            maxTransionId++;
            return maxTransionId;
        }

        #endregion
    }
}